/******************************************************************
 * 功能：用于控制恒流模块，采用DAC方式控制恒流模块的输出电流
 * 作者：WU555
 * 时间：2023-10-19
 *******************************************************************/
#include "DCMCtrl.h"
#include "MSP_DAC.h"
#include "math.h"
#include <stdlib.h>
#include "ee.h"
#include "eeConfig.h"

extern ADC_HandleTypeDef hadc1;
extern ADC_HandleTypeDef hadc2;
extern ADC_HandleTypeDef hadc3;
extern ADC_HandleTypeDef hadc4;
extern ADC_HandleTypeDef hadc5;
extern DMA_HandleTypeDef hdma_adc1;
extern DMA_HandleTypeDef hdma_adc2;
extern DMA_HandleTypeDef hdma_adc3;
extern DMA_HandleTypeDef hdma_adc4;
extern DMA_HandleTypeDef hdma_adc5;

extern DAC_HandleTypeDef hdac1;
extern DAC_HandleTypeDef hdac2;
extern DAC_HandleTypeDef hdac3;
extern DAC_HandleTypeDef hdac4;
extern OPAMP_HandleTypeDef hopamp1;
extern OPAMP_HandleTypeDef hopamp4;

DCModule_AnalogIn_t DCM_AnalogIn_Buffer;

/* PLC发送过来的参数 */
OUTDATAValueHandle _DCM_OUTDataValue;

/* 延迟显示设备状态的参数 */
uint32_t DelayShow_DevState_MaxTime = 2000;     //显示2s，再清除
uint32_t DelayShow_DevState_LastTime[DCModuleNum] = {0, 0, 0, 0, 0};

float DCM_SetOutCurr_Buffer[DCModuleNum];           //用于保存当前设置的输出电流值
float DCM_Real_OutPutCurr_Buffer[DCModuleNum];           //用于保存当前实际的输出电流值

//uint8_t DCM_Adjust_OutCurr_Buffer[DCModuleNum] = {100, 100, 100, 100, 100};     //用于保存设置的调整电流的百分比值

uint8_t DCM_Fault_Flag[DCModuleNum];
uint8_t DCM_Pdet_Flag[DCModuleNum];
uint8_t DCM_Fault_PinValue_Cache[DCModuleNum];
uint8_t DCM_Pdet_PinValue_Cache[DCModuleNum];
float DCM_GetOutCurr_Cache[DCModuleNum];

DCModule_State_t DCM_State[DCModuleNum];
DCModule_State_t DCM_State_Cache[DCModuleNum];

float DCM_OUTCurr_Max       = 20.0; // 输出最大电流
float DCM_OUTCurr_Min       = 0.8;  // 输出最小电流
float DCM_OUTCurr_Limit     = 0.5;  // 判断有无电流的最小值
uint8_t ADJ_Curr_Gear_Max   = 150;
uint8_t ADJ_Curr_Gear_Min   = 50;

/********************** 需要在其他文件中使用的参数，全局变量 ***************************/
float Get_OUTCurr_Volt[DCModuleNum];
float Get_SetCurr_Volt[DCModuleNum] = {0, 0, 0, 0, 0};
//uint8_t Get_AdjustCurr_Now[DCModuleNum];

uint8_t DCM_SetCurr_Now_Cnt[DCModuleNum] = {0, 0, 0, 0, 0};

uint8_t _CurrIsOutofSet_Cnt[DCModuleNum] = {0, 0, 0, 0, 0};       //读取到的电流值超过设置值的次数

#ifdef USE_AdjustFunc
DCM_Adjust_FromPLC_t DCM_Adjust_Flag[DCModuleNum] = {0, 0, 0, 0, 0};
uint8_t DCM_AdjustOutCurr_Gear_Buffer[DCModuleNum][ADJ_Curr_Gear_Num];      //用于保存当前设置的校准值：百分比数值 
#endif

/*********************************************************************************/

float _KFP_Last_out = 0; // 用于卡尔曼滤波
KFP KFP_DCM1 = {0.0, 1, 0, 0.0, 0.0, 0.01, 4.5};
KFP KFP_DCM2 = {0.0, 1, 0, 0.0, 0.0, 0.01, 4.5};
KFP KFP_DCM3 = {0.0, 1, 0, 0.0, 0.0, 0.01, 2.5};
KFP KFP_DCM4 = {0.0, 1, 0, 0.0, 0.0, 0.01, 2.5};
KFP KFP_DCM5 = {0.0, 1, 0, 0.0, 0.0, 0.01, 4.5};        //KFP KFP_DCM5 = {0.0, 1, 0, 0.0, 0.0, 0.008, 8.5};
//KFP KFP_DCMV1 = {0.0, 1, 0, 0.0, 0.0, 0.01, 2.5};


#ifdef USE_EEPROMFunc
uint8_t have_para_inflash = 0;              //用于判断参数是否在flash中
#endif



/* 输出电流控制信号ctrl，分段比例系数 
 * 0.8A~1.5A,   1.5A~2.5A,    2.5A~3.5A,    3.5A~4.5A,    4.5A~5.5A,   5.5A~6.5A,   6.5A~7.5A,   7.5A~8.5A,   8.5A~9.5A,   9.5A~10.5A, 
 * 10.5A~11.5A, 11.5A~12.5A,  12.5A~13.5A,  13.5A~14.5A,  14.5A~15.5A, 15.5A~16.5A, 16.5A~17.5A, 17.5A~18.5A, 18.5A~19.5A, 19.5A~20.0A
*/
//调高，电流减小
uint16_t DCM_SetCurr_Gain_Default[DCModuleNum][DCM_Gain_Num] = {
    /* 1     2     3     4     5     6     7     8     9     10    11    12    13    14    15    16    17    18    19    20    */
    {1344, 1340, 1354, 1352, 1351, 1351, 1348, 1345, 1344, 1337, 1327, 1322, 1320, 1318, 1315, 1312, 1310, 1308, 1308, 1308},   //DCM1
    {1336, 1336, 1356, 1354, 1354, 1353, 1349, 1345, 1341, 1333, 1326, 1323, 1321, 1320, 1317, 1315, 1311, 1313, 1313, 1313},   //DCM2 5
    {1334, 1370, 1363, 1362, 1364, 1362, 1358, 1352, 1341, 1331, 1327, 1324, 1322, 1320, 1318, 1317, 1317, 1316, 1317, 1317},   //DCM3 ok
    {1334, 1334, 1332, 1348, 1349, 1348, 1347, 1345, 1341, 1334, 1323, 1318, 1315, 1313, 1311, 1310, 1309, 1307, 1305, 1305},   //DCM4
    {1345, 1343, 1359, 1356, 1358, 1358, 1355, 1350, 1345, 1334, 1324, 1320, 1319, 1317, 1316, 1315, 1313, 1312, 1312, 1312},   //DCM5     
};
uint16_t DCM_SetCurr_Gain_Flash[DCModuleNum][DCM_Gain_Num];


/* 输出电流反馈信号curr，分段比例系数 
 * 0.8A~1.5A,   1.5A~2.5A,    2.5A~3.5A,    3.5A~4.5A,    4.5A~5.5A,   5.5A~6.5A,   6.5A~7.5A,   7.5A~8.5A,   8.5A~9.5A,   9.5A~10.5A,
 * 10.5A~11.5A, 11.5A~12.5A,  12.5A~13.5A,  13.5A~14.5A,  14.5A~15.5A, 15.5A~16.5A, 16.5A~17.5A, 17.5A~18.5A, 18.5A~19.5A, 19.5A~20.0A
*/
uint16_t DCM_OUTCurr_Gain_Default[DCModuleNum][DCM_Gain_Num] = {
    /*1    2    3    4    5    6    7    8    9    10   11   12   13   14   15   16   17   18   19   20     */
    {736, 734, 739, 740, 743, 739, 737, 734, 732, 731, 727, 726, 725, 724, 726, 722, 722, 721, 724, 724},                   //DCM1
    {730, 730, 740, 740, 736, 734, 735, 733, 732, 730, 724, 723, 722, 720, 719, 719, 720, 719, 717, 717},                   //DCM2
    {735, 741, 743, 737, 735, 729, 729, 731, 729, 719, 723, 712, 721, 716, 718, 717, 708, 717, 717, 717},                   //DCM3
    {748, 741, 732, 739, 740, 738, 737, 736, 734, 732, 726, 726, 724, 723, 722, 723, 719, 717, 717, 717},                   //DCM4          
    {735, 736, 741, 742, 741, 738, 740, 736, 734, 733, 728, 727, 726, 725, 725, 722, 721, 720, 717, 717},                   //DCM5          
}; 
uint16_t DCM_OUTCurr_Gain_Flash[DCModuleNum][DCM_Gain_Num];

/* 用于PLC发送过来的校准参数操作 */
uint8_t Adj_DCM_Curr_Flash[DCModuleNum][ADJ_Curr_Gear_Num];     //PLC发送过来的校准参数，百分比系数 数值50～150，分段校准，满量程15A，总共分10段
//uint8_t Start_DCM_Adjust_Flag = 0;  //位标记    0000 0000   {0, 0, 0, 0, 0};

void dcm_init(void)
{
    ADC_CONV_COMPLETE_FLAG = 0;

    memset(DCM_Fault_PinValue_Cache, 0, sizeof(DCM_Fault_PinValue_Cache));
    memset(DCM_Pdet_PinValue_Cache, 0, sizeof(DCM_Pdet_PinValue_Cache));
    memset(DCM_SetOutCurr_Buffer, 0, sizeof(DCM_SetOutCurr_Buffer));
    memset(Adj_DCM_Curr_Flash, 100, sizeof(uint8_t) * DCModuleNum * ADJ_Curr_Gear_Num);
    memset(DCM_Real_OutPutCurr_Buffer, 0, sizeof(DCM_Real_OutPutCurr_Buffer));

    /* 从FLASH读取参数(目前有3个)：Adj_DCM_Curr校准百分比(PLC设置的)， SetCurr_Gain比例系数 和 OutCurr_Gain比例系数 */
    dcm_read_data_fromFLASH();
    //LOG("have_para_inflash : %d\r\n", have_para_inflash);

    /*启动所有模拟输出通道*/
    for (int i = 0; i < DCModuleNum; i++)
        start_analogout(i);

    /*复位所有模拟输出通道*/
    for (int i = 0; i < DCModuleNum; i++)
        set_analogout(i, 0);

    /*启动所有ADC通道*/
    for (int i = 0; i < DCModuleNum; i++)
        start_analogin(i);
}

/**
 * @brief 用于判断PLC发送过来的参数是否设置有问题
 * 
 * @param ch 
 * @param set_outcurr 
 * @param adjust_gear 
 */
void dcm_save_outcurrpara(uint8_t ch, float set_outcurr, uint8_t adjust_gear)
{
    //DCM_SetOutCurr_Buffer[ch] = 0;
    /* 参数为0的话，不做任何处理 */
    if ((set_outcurr == 0) && (adjust_gear == 0))
        return;

    /* 1、 判断设置的电流值是否超过阀值，只接收0.8A～20A之间的数值 */
    if (set_outcurr != 0)
    {
        if ((set_outcurr > DCM_OUTCurr_Max) || (set_outcurr < DCM_OUTCurr_Min))
        {
            //LOG_error("set out current value error !!! channel %d, curr : %f\r\n", ch, set_outcurr);
            DCM_State[ch] = DCMState_Set_OutCurr_Err;
            return;
        }
        DCM_SetOutCurr_Buffer[ch] = set_outcurr;
    }

    /* 2、 判断设置的校准的百分比数值是否超过阀值，只接收50～150之间的数值 */
    if (adjust_gear != 0)
    {
        if ((adjust_gear > ADJ_Curr_Gear_Max) || (adjust_gear < ADJ_Curr_Gear_Min))
        {
            //LOG_error("set adjust gear value error !!! channel %d, gear : %d\r\n", ch, adjust_gear);
            DCM_State[ch] = DCMState_Set_AdjustGear_Err;
            return;
        }
    }

//    LOG("dcm_save_outcurrpara success .........\r\n");
//    if (set_outcurr != 0)
//        DCM_SetOutCurr_Buffer[ch] = set_outcurr;
  
    DCM_State[ch] = DCMState_SetPara_OK;
}

void open_dcm_outcurr(uint8_t ch)
{
    if ((DCM_State[ch] == DCMState_Set_OutCurr_Err) || (DCM_State[ch] == DCMState_Set_AdjustGear_Err) || (DCM_State[ch] == DCMState_Adjust_OutCurr_Err))
        return;

    uint8_t gear_i = Get_AdjCurrGear_NO(DCM_SetOutCurr_Buffer[ch]);
    /* 如果校准参数超过范围，则默认都用100的数值，即100% */
    if ((Adj_DCM_Curr_Flash[ch][gear_i] < ADJ_Curr_Gear_Min) || (Adj_DCM_Curr_Flash[ch][gear_i] > ADJ_Curr_Gear_Max))
        Adj_DCM_Curr_Flash[ch][gear_i] = 100;

    float adjust_outcurr = DCM_SetOutCurr_Buffer[ch] * (Adj_DCM_Curr_Flash[ch][gear_i] / 100.0);
    dcm_set_outcurrent(ch, adjust_outcurr);
    dcm_enable_output(ch, 1);
}

void close_dcm_outcurr(uint8_t ch)
{
    dcm_enable_output(ch, 0);
    dcm_set_outcurrent(ch, 0);
    memset(_CurrIsOutofSet_Cnt, 0, sizeof(_CurrIsOutofSet_Cnt));
}

uint8_t dcm_enable_output(uint8_t ch, uint8_t en)
{
    if (ch == DCModule_1)
        DCM1_EN(en);
    else if (ch == DCModule_2)
        DCM2_EN(en);
    else if (ch == DCModule_3)
        DCM3_EN(en);
    else if (ch == DCModule_4)
        DCM4_EN(en);
    else if (ch == DCModule_5)
    {
        DCM5_EN(en);
    }
    else
        return 0;

    /* 关闭恒流模块的同时，需要把DAC引脚设为0 */
    if (en == 0)
        set_analogout(ch, 0);

    return 1;
}

uint8_t dcm_read_enable_value(uint8_t ch)
{
    uint8_t en_value = 0;
    switch (ch)
    {
    case DCModule_1:
        en_value = HAL_GPIO_ReadPin(DCM1_EN_Port, DCM1_EN_Pin);
        break;

    case DCModule_2:
        en_value = HAL_GPIO_ReadPin(DCM2_EN_Port, DCM2_EN_Pin);
        break;

    case DCModule_3:
        en_value = HAL_GPIO_ReadPin(DCM3_EN_Port, DCM3_EN_Pin);
        break;

    case DCModule_4:
        en_value = HAL_GPIO_ReadPin(DCM4_EN_Port, DCM4_EN_Pin);
        break;

    case DCModule_5:
        en_value = HAL_GPIO_ReadPin(DCM5_EN_Port, DCM5_EN_Pin);
        break;

    default:
        LOG_error("dcm_read_enable_value channel error!\r\n");
    }
    return en_value;
}

/**
 * @brief 设置某一恒流模块的输出电流值
 * 
 * @param ch 指向第几个恒流模块
 * @param value 电流值 0～20A
 * @return uint8_t 1:表示设置成功
 */
uint8_t dcm_set_outcurrent(uint8_t ch, float curr)
{
    float volt;
#if 0
    /* 保存设置的输出电流值 */
    //DCM_SetOutCurr_Buffer[ch] = curr;
    /* 输出电流设置超过阀值的话，报错 */
    if 
    if ((curr > DCM_OUTCurr_Max) || (curr < DCM_OUTCurr_Min))
    {
        if (curr != 0)
        {
            LOG_error("dcm_set_outcurrent error !!! channel %d, curr : %f\r\n", ch, curr);
            return 0;
        }
    }
#endif

#if 0
    /* 加上百分比值 */
    float curr_adjust = Get_AdjustCurr(ch) * curr / 100.0;       //curr * curr_adjust / 100.0

    if ((curr_adjust > DCM_OUTCurr_Max) || (curr_adjust < DCM_OUTCurr_Min))
    {
        if (curr_adjust != 0)
        {
            LOG_error("in dcm_set_outcurrent......dcm_set adjust out curr error !!! channel %d, curr : %f\r\n", ch, curr_adjust);
            DCM_Adjust_Flag[ch] = DCM_Adjust_FromPLC_SetData_Err;
            return 0;
        }
    }
    else
        DCM_Adjust_Flag[ch] = DCM_Adjust_FromPLC_Default;
#endif

    DCM_SetCurr_Now_Cnt[ch] = round(curr) - 1;
    
    volt = curr * DCM_Gain_Multi / DCM_SetCurr_Gain_Flash[ch][DCM_SetCurr_Now_Cnt[ch]];
    Get_SetCurr_Volt[ch] = volt;
    
    uint32_t data = (uint32_t)(volt * DCM_DAC_MAX * DCM_Vref_Multi / DCM_Vref);
    set_analogout(ch, data);
    return 1;
}

/**
 * @brief 设置某一恒流模块的输出电流值对应的电压值
 * 
 * @param ch 指向第几个恒流模块
 * @return 设置某一恒流模块的输出电流值对应的电压值
 */
float dcm_get_setcurr_volt(uint8_t ch)
{
    return Get_SetCurr_Volt[ch];
}

/**
 * @brief 保存某一恒流模块的当前的调整后的电流值
 * 
 * @param ch 指向第几个恒流模块
 * @param curr 设置的电流值
 * @return 返回经过校准后的实际电流值
 */
#if 0
float dcm_set_adjustcurr(uint8_t ch, float curr)
{
    /* 保存设置的输出电流值 */
    DCM_SetOutCurr_Buffer[ch] = curr;


}
#endif

/**
 * @brief 设置某一恒流模块的调整电流值
 * 
 * @param ch 指向第几个恒流模块
 * @param value 调整电流的百分比 50～150， 50 = 50%
 * @return uint8_t 1:表示设置成功
 */
#if 0
uint8_t dcm_set_adjustcurr_gear(uint8_t ch, uint8_t value)
{
    if (value == 0)
        return 1;
        
    /* 输出电流设置超过阀值的话，报错 */
    if ((value > 150) || (value < 50) || (value < 0))
    {
        LOG_error("dcm_set adjust out curr error !!! channel %d, curr : %d\r\n", ch, value);
        DCM_Adjust_Flag[ch] = DCM_Adjust_FromPLC_SetData_Err;
        return 0;
    }

    /* 保存校准的百分比值 */
    DCM_AdjustOutCurr_Gear_Buffer[ch] = value;
    return 1;
}
#endif

/**
 * @brief 启动校准进程
 * 
 * @param ch 
 * @param value 校准参数范围50～150
 */
void dcm_start_adjust_process(uint8_t ch, uint8_t gear_i, uint8_t adjust_gear)
{     
    /* 3、 判断校准后的电流值是否超过阀值 ： 20A > (set_outcurr * adjust_gear) > 0.8A */
    float adj_outcurr = DCM_SetOutCurr_Buffer[ch] * (adjust_gear / 100.0);
    if ((adj_outcurr > DCM_OUTCurr_Max) || (adj_outcurr < DCM_OUTCurr_Min))
    {
        //LOG_error("adjust out current value error !!! channel %d, adj_outcurr : %f\r\n", ch, adj_outcurr);
        DCM_State[ch] = DCMState_Adjust_OutCurr_Err;
        return;
    }
    else
        DCM_State[ch] = DCMState_SetPara_OK;
#if 0
    if ((value > 150) || (value < 50) || (value < 0))
    {
        LOG_error("dcm_set adjust out curr error !!! channel %d, adjust value : %d\r\n", ch, value);
        DCM_Adjust_Flag[ch] = DCM_Adjust_FromPLC_SetData_Err;
        return;
    }
    else
        DCM_Adjust_Flag[ch] = DCM_Adjust_FromPLC_Default;
#endif
    
    if (DCM_State[ch] != DCMState_Set_AdjustGear_Err)
    {
        Adj_DCM_Curr_Flash[ch][gear_i] = adjust_gear;       //DCM_AdjustOutCurr_Gear_Buffer[ch];
        //DCM_AdjustOutCurr_Gear_Buffer[ch][gear_i] = adjust_gear;
    }
}

/**
 * @brief 结束校准进程
 * 
 * @param ch 
 */
void dcm_end_adjust_process(uint8_t ch)
{
    if ((DCM_State[ch] == DCMState_Adjust_OutCurr_Err) || (DCM_State[ch] == DCMState_Set_AdjustGear_Err))
        return;

    uint8_t adj_dcm_curr[100];
    memset(adj_dcm_curr, 0, sizeof(adj_dcm_curr));
    adj_dcm_curr[0] = lowByte(ee_use_StartFrame);
    adj_dcm_curr[1] = highByte(ee_use_StartFrame); 
    memcpy(adj_dcm_curr + 2, Adj_DCM_Curr_Flash, sizeof(uint8_t) * DCModuleNum * ADJ_Curr_Gear_Num);
    if (dcm_saved_data_toFLASH(_EE_USE_AdjustCurr_START_ADDR, sizeof(adj_dcm_curr), adj_dcm_curr) == 1)
        DCM_Adjust_Flag[ch] = DCM_Adjust_FromPLC_Saved;
    else
        DCM_Adjust_Flag[ch] = DCM_Adjust_FromPLC_Save_Err;

}

/**
 * @brief 获取某一恒流模块的校准参数
 *
 * @param ch 指向第几个恒流模块
 * @return uint8_t 返回当前恒流模块的校准参数
 */
#if 1
uint8_t dcm_get_adjustcurrgear(uint8_t ch)
{
    uint8_t gear_i = Get_AdjCurrGear_NO(DCM_SetOutCurr_Buffer[ch]);
    return Adj_DCM_Curr_Flash[ch][gear_i];
}
#endif

/**
 * @brief 获取某一恒流模块的输出电流值
 *
 * @param ch 指向第几个恒流模块
 * @return float 返回当前恒流模块的输出电流值
 */
float dcm_get_outcurrent(uint8_t ch)
{
    float curr, currvolt;
    float curr_adjust_kfp;
    float curr_adjust;
    
    uint32_t c_u32;
    switch (ch)
    {
    case DCModule_1:
        c_u32 = DCM_AnalogIn_Buffer.DCM1_ANALOGIN[DCM1_OUTCurr_Index];
        break;

    case DCModule_2:
        c_u32 = DCM_AnalogIn_Buffer.DCM2_ANALOGIN[DCM2_OUTCurr_Index];
        break;

    case DCModule_3:
        c_u32 = DCM_AnalogIn_Buffer.DCM3_ANALOGIN[DCM3_OUTCurr_Index];
        break;

    case DCModule_4:
        c_u32 = DCM_AnalogIn_Buffer.DCM4_ANALOGIN[DCM4_OUTCurr_Index];
        break;

    case DCModule_5:
        c_u32 = DCM_AnalogIn_Buffer.DCM5_ANALOGIN[DCM5_OUTCurr_Index];
        break;

    default:
        LOG_error("get outcurrent error!\r\n");
        c_u32 = 0;
    }
    
    currvolt = (float)(c_u32 * DCM_Vref / (float)DCM_Vref_Multi / DCM_DAC_MAX);
    Get_OUTCurr_Volt[ch] = currvolt;

    curr = currvolt * DCM_OUTCurr_Gain_Flash[ch][DCM_SetCurr_Now_Cnt[ch]] / (float)DCM_Gain_Multi;   //从flash读取的参数
    if (curr > DCM_OUTCurr_Limit)
    {
        DCM_Real_OutPutCurr_Buffer[ch] = curr;          //保存实际的输出电流值

        /* 扣除百分比 */
        uint8_t gear_i = Get_AdjCurrGear_NO(DCM_SetOutCurr_Buffer[ch]);
        curr_adjust = curr * 100 / (float)Adj_DCM_Curr_Flash[ch][gear_i];

        /* 检测到的电流反馈值大于设定值 + 0.1A的时候，强制设置为电流设置值+0.1A */
        //if ((curr > (DCM_SetOutCurr_Buffer[ch] + 0.1)) || (curr < (DCM_SetOutCurr_Buffer[ch] + 0.1)))
        if (fabs(curr_adjust - DCM_SetOutCurr_Buffer[ch]) > 0.1)
        {
            if (_CurrIsOutofSet_Cnt[ch] < 50)
            {
                curr_adjust = DCM_SetOutCurr_Buffer[ch] + 0.1;
                _CurrIsOutofSet_Cnt[ch]++;
                //LOG("......._CurrIsOutofSet_Cnt = %d\r\n", _CurrIsOutofSet_Cnt);
            }
        }
        else
        {
            _CurrIsOutofSet_Cnt[ch] = 0;
        }
        /* 进行卡尔曼滤波 */
#ifdef USE_KFP
        curr_adjust_kfp = kalmanFilter(KFP_DCM_Curr_Index(ch), curr_adjust);     
#else
        curr_adjust_kfp = curr_adjust;
#endif
    }
    else
    {
        curr_adjust_kfp = 0;
        DCM_Real_OutPutCurr_Buffer[ch] = 0;          //保存实际的输出电流值
    }
     
    return curr_adjust_kfp;
}

/**
 * @brief 获取某一恒流模块的‘电流反馈值超过设置的电流值’的次数
 *
 * @param ch 指向第几个恒流模块
 * @return uint8_t 超过的次数
 */
uint8_t dcm_get_currisoutofset_num(uint8_t ch)
{
    return _CurrIsOutofSet_Cnt[ch];
}

/**
 * @brief 获取某一恒流模块的输出电流值对应的电压值
 *
 * @param ch 指向第几个恒流模块
 * @return float 返回当前恒流模块的输出电流值对应的电压值
 */
float dcm_get_outcurr_volt(uint8_t ch)
{
    return Get_OUTCurr_Volt[ch];
}

/**
 * @brief 获取某一恒流模块的实际输出电流值
 * 
 * @param ch 
 * @return float 实际输出的电流值
 */
float dcm_get_real_outputcurr(uint8_t ch)
{
    return DCM_Real_OutPutCurr_Buffer[ch];
}

/**
 * @brief 获取某一恒流模块的输出电压
 *
 * @param ch 指向第几个恒流模块
 * @return float 返回当前恒流模块的输出电压
 */
float dcm_get_outvoltage(uint8_t ch)
{
    float volt, volt_v;
    uint32_t v_u32;
    switch (ch)
    {
    case DCModule_1:
        v_u32 = DCM_AnalogIn_Buffer.DCM1_ANALOGIN[DCM1_OUTVolt_Index];
        break;

    case DCModule_2:
        v_u32 = DCM_AnalogIn_Buffer.DCM2_ANALOGIN[DCM2_OUTVolt_Index];
        break;

    case DCModule_3:
        v_u32 = DCM_AnalogIn_Buffer.DCM3_ANALOGIN[DCM3_OUTVolt_Index];
        break;

    case DCModule_4:
        v_u32 = DCM_AnalogIn_Buffer.DCM4_ANALOGIN[DCM4_OUTVolt_Index];
        break;

    case DCModule_5:
        v_u32 = DCM_AnalogIn_Buffer.DCM5_ANALOGIN[DCM5_OUTVolt_Index];
        break;

    default:
        LOG_error("get OUTVoltage error!\r\n");
        return NAN;
    }
    //LOG("%ld ", v_u32);
    volt_v = (float)(v_u32 * DCM_Vref / (float)DCM_Vref_Multi / DCM_DAC_MAX);
    
    volt = volt_v * DCM_OUTVolt_Gain / (float)DCM_Gain_Multi;

    return volt;
}

/**
 * @brief 用于判断某一恒流模块的状态
 *
 * @param ch
 * @return int
 */
uint8_t DCMState_OUT_Break_Check[DCModuleNum] = {0, 0, 0, 0, 0}; 
uint8_t DCMState_OUT_OverCurr_Check[DCModuleNum] = {0, 0, 0, 0, 0}; 
const uint8_t DCMState_Check_MaxNum = 8; 
DCModule_State_t dcm_get_dcmstate(uint8_t ch)
{
    /*1. 先判断PLC发送过来的参数，是否超过阀值？，报错: 40101 or 40201 or 40301 */
    if ((DCM_State[ch] == DCMState_Set_OutCurr_Err) || (DCM_State[ch] == DCMState_Set_AdjustGear_Err) || (DCM_State[ch] == DCMState_Adjust_OutCurr_Err))
    {
        return DCM_State[ch];
    }

#ifdef USE_AdjustFunc
    /* 7. 判断是否有校准状态变化 */
    if (DCM_Adjust_Flag[ch] != DCM_Adjust_FromPLC_Default)
    {
        if (DCM_Adjust_Flag[ch] == DCM_Adjust_FromPLC_Save_Err)
            DCM_State[ch] = DCMState_Adjust_Save_Err;
        else if (DCM_Adjust_Flag[ch] == DCM_Adjust_FromPLC_Saved)
        {
            DCM_State[ch] = DCMState_Adjust_Saved;
            DCM_Adjust_Flag[ch] = DCM_Adjust_FromPLC_ShowTime;
            DelayShow_DevState_LastTime[ch] = HAL_GetTick();
        }
        else if (DCM_Adjust_Flag[ch] == DCM_Adjust_FromPLC_ShowTime)
        {
            if (HAL_GetTick() - DelayShow_DevState_LastTime[ch] > DelayShow_DevState_MaxTime)
            {
                DCM_State[ch] = DCMState_Work;      //DCMState_Adjust_Saved;
                DCM_Adjust_Flag[ch] = DCM_Adjust_FromPLC_Default;
            }
        }
        return DCM_State[ch];
    }
#endif

    /* 2. 先判断是否有输入电压: 30201 */
    if (dcm_get_pdet(ch) == DCM_No_INVolt)
    {
        DCM_State[ch] = DCMState_IN_NoVolt;
        return DCM_State[ch];
    }

    /* 3. 判断电流反馈值 是否超过设置的电流值太多: 30101 */
    if ((dcm_read_enable_value(ch) == Enable_DCM) && (dcm_get_outcurrent(ch) > DCM_OUTCurr_Limit) && ((dcm_get_outcurrent(ch) - DCM_SetOutCurr_Buffer[ch]) > DCM_OUTCurr_Limit)) 
    {
        /* 二次判断，避免误报： 判断5次 */
        if (DCMState_OUT_OverCurr_Check[ch] > DCMState_Check_MaxNum)
        {
            DCM_State[ch] = DCMState_OUT_OverCurr;
            return DCM_State[ch];
        }
        DCMState_OUT_OverCurr_Check[ch]++;
    }
    else
    {
        DCMState_OUT_OverCurr_Check[ch] = 0;
    }

    /* 4. 判断输出是否断路：30301；断路有几种情况：未接负载、输出线断开、接触不良 */
    if ((dcm_read_enable_value(ch) == Enable_DCM) && (dcm_get_outcurrent(ch) < DCM_OUTCurr_Limit))
    {
        /* 二次判断，避免误报： 判断2次 */
        if (DCMState_OUT_Break_Check[ch] >= 1)
        {
            DCM_State[ch] = DCMState_OUT_Break;
            return DCM_State[ch];
        }
        DCMState_OUT_Break_Check[ch]++;
    }
    else
    {
        DCMState_OUT_Break_Check[ch] = 0;
    }

    /* 5. 判断输出电压是否过高：  */

    /* 6. 判断输出电压是否过低：  */

#if 0    
    /* 0. 判断恒流模块是否报Fault错误: 30401 */
    if (dcm_get_dcmfault(ch) == DCM_Fault)
    {
        DCM_State[ch] = DCMState_Fault;
        return DCM_State[ch];
    }
#endif

    DCM_State[ch] = DCMState_Work;
    return DCM_State[ch];
}

#if 0       //def USE_AdjustFunc
void dcm_write_adjustflag(uint8_t ch, DCM_Adjust_FromPLC_t dcmadj)
{
    DCM_Adjust_Flag[ch] = 10500 + dcmadj;
}
#endif

/**
 * @brief 获取某一恒流模块的fault信号
 * 恒流模块有异常，会报一个fault信号 1:错误； 0:正常
 * @param ch
 * @return uint8_t
 */
uint8_t dcm_get_dcmfault(uint8_t ch)
{
    uint8_t faultpinvalue = dcm_read_fault_value(ch);
    if (DCM_Fault_PinValue_Cache[ch] == faultpinvalue)
        DCM_Fault_Flag[ch] = faultpinvalue;
    else
        DCM_Fault_PinValue_Cache[ch] = faultpinvalue;

    return DCM_Fault_Flag[ch];
}

#if 1
uint8_t dcm_read_fault_value(uint8_t ch)
{
    uint8_t fault = 0;
    switch (ch)
    {
    case DCModule_1:
        fault = HAL_GPIO_ReadPin(DCM1_Fault_Port, DCM1_Fault_Pin);
        break;

    case DCModule_2:
        fault = HAL_GPIO_ReadPin(DCM2_Fault_Port, DCM2_Fault_Pin);
        break;

    case DCModule_3:
        fault = HAL_GPIO_ReadPin(DCM3_Fault_Port, DCM3_Fault_Pin);
        break;

    case DCModule_4:
        fault = HAL_GPIO_ReadPin(DCM4_Fault_Port, DCM4_Fault_Pin);
        break;

    case DCModule_5:
#ifndef DEVBoardG4
        fault = HAL_GPIO_ReadPin(DCM5_Fault_Port, DCM5_Fault_Pin);
#else
        // LOG("is in DEVBoardG4, no DCM5_fault\r\n");
#endif
        break;

    default:
        LOG_error("dcm_get_dcmfault channel error!\r\n");
    }
    return fault;
}
#endif

/**
 * @brief 获取某一恒流模块的输入电压状态
 * 1:有电压输入； 0:无输入电压
 * @param ch
 * @return uint8_t
 */
uint8_t dcm_get_pdet(uint8_t ch)
{
    uint8_t pdetpinvalue = dcm_read_pdet_value(ch);
    if (DCM_Pdet_PinValue_Cache[ch] == pdetpinvalue)
        DCM_Pdet_Flag[ch] = pdetpinvalue;
    else
        DCM_Pdet_PinValue_Cache[ch] = pdetpinvalue;

    return DCM_Pdet_Flag[ch];
}

#if 1
uint8_t dcm_read_pdet_value(uint8_t ch)
{
    uint8_t pdet = 0;
    switch (ch)
    {
    case DCModule_1:
        pdet = HAL_GPIO_ReadPin(DCM1_Pdet_Port, DCM1_Pdet_Pin);
        break;

    case DCModule_2:
        pdet = HAL_GPIO_ReadPin(DCM2_Pdet_Port, DCM2_Pdet_Pin);
        break;

    case DCModule_3:
        pdet = HAL_GPIO_ReadPin(DCM3_Pdet_Port, DCM3_Pdet_Pin);
        break;

    case DCModule_4:
        pdet = HAL_GPIO_ReadPin(DCM4_Pdet_Port, DCM4_Pdet_Pin);
        break;

    case DCModule_5:
        pdet = HAL_GPIO_ReadPin(DCM5_Pdet_Port, DCM5_Pdet_Pin);
        break;

    default:
        LOG_error("dcm_get_pdet channel error!\r\n");
    }
    return pdet;
}
#endif

/**
 * @brief 启动指定通道的DAC模拟输出
 *
 * @param ch 通道号
 */
void start_analogout(uint8_t ch)
{
    switch (ch)
    {
    case DCModule_1:
        HAL_DAC_Start(&hdac1, DAC_CHANNEL_1);
        break;

    case DCModule_2:
        HAL_DAC_Start(&hdac1, DAC_CHANNEL_2);
        break;

    case DCModule_3:
        HAL_DAC_Start(&hdac2, DAC_CHANNEL_1);
        break;

    case DCModule_4:
        HAL_DAC_Start(&hdac3, DAC_CHANNEL_1);
        HAL_OPAMP_Start(&hopamp1);
        break;

    case DCModule_5:
        HAL_DAC_Start(&hdac4, DAC_CHANNEL_1);
        HAL_OPAMP_Start(&hopamp4);
        break;

    default:
        LOG_error("start analogout channel error!\r\n");
        break;
    }
}

/**
 * @brief 停止指定通道的DAC模拟输出
 *
 * @param ch 通道号
 */
void stop_analogout(uint8_t ch)
{
    switch (ch)
    {
    case DCModule_1:
        HAL_DAC_Stop(&hdac1, DAC_CHANNEL_1);
        break;

    case DCModule_2:
        HAL_DAC_Stop(&hdac1, DAC_CHANNEL_2);
        break;

    case DCModule_3:
        HAL_DAC_Stop(&hdac2, DAC_CHANNEL_1);
        break;

    case DCModule_4:
        HAL_DAC_Stop(&hdac3, DAC_CHANNEL_1);
        HAL_OPAMP_Stop(&hopamp1);
        break;

    case DCModule_5:
        HAL_DAC_Stop(&hdac4, DAC_CHANNEL_1);
        HAL_OPAMP_Stop(&hopamp4);
        break;

    default:
        LOG_error("stop analogout channel error!\r\n");
        break;
    }
}

/**
 * @brief 设置DAC模拟输出通道的值
 *
 * @param ch 通道号
 * @param value 输出值
 */
void set_analogout(uint8_t ch, uint32_t value)
{
    //LOG("set_analogout....%d, ......value : %ld \r\n", ch, value);
    switch (ch)
    {
    case DCModule_1:
        HAL_DAC_SetValue(&hdac1, DAC_CHANNEL_1, DAC_ALIGN_12B_R, value);
        break;
    case DCModule_2:
        HAL_DAC_SetValue(&hdac1, DAC_CHANNEL_2, DAC_ALIGN_12B_R, value);
        break;
    case DCModule_3:
        //LOG("value 3 : %ld\r\n", value);
        HAL_DAC_SetValue(&hdac2, DAC_CHANNEL_1, DAC_ALIGN_12B_R, value);
        break;
    case DCModule_4:
        HAL_DAC_SetValue(&hdac3, DAC_CHANNEL_1, DAC_ALIGN_12B_R, value);
        break;
    case DCModule_5:
        HAL_DAC_SetValue(&hdac4, DAC_CHANNEL_1, DAC_ALIGN_12B_R, value);
        break;
    default:
        LOG_error("analog out channel error!\r\n");
        break;
    }
}

void start_analogin(uint8_t ch)
{
    switch (ch)
    {
    case DCModule_1:
#ifndef DEVBoardG4
        /* Run the ADC calibration in single-ended mode */
        if (HAL_ADCEx_Calibration_Start(&hadc2, ADC_SINGLE_ENDED) != HAL_OK)
            Error_Handler();
        
        /* Start ADC conversion used dma*/
        // if (HAL_ADC_Start_DMA(&hadc2) != HAL_OK)    //, DCM_ANALOGIN_Size) != HAL_OK)
        if (HAL_ADC_Start_DMA(&hadc2, (uint32_t *)DCM_AnalogIn_Buffer.DCM1_ANALOGIN, DCM_ANALOGIN_Size) != HAL_OK)
            Error_Handler();
#endif
        break;

    case DCModule_2:
        /* Run the ADC calibration in single-ended mode */
        if (HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED) != HAL_OK)
            Error_Handler();
    
        /* Start ADC conversion used dma*/
        // if (HAL_ADC_Start_DMA(&hadc1, (uint32_t *)&tbuffer, 1) != HAL_OK)
        if (HAL_ADC_Start_DMA(&hadc1, (uint32_t *)DCM_AnalogIn_Buffer.DCM2_ANALOGIN, DCM_ANALOGIN_Size) != HAL_OK)
            Error_Handler();
        break;

    case DCModule_3:
        /* Run the ADC calibration in single-ended mode */
        if (HAL_ADCEx_Calibration_Start(&hadc3, ADC_SINGLE_ENDED) != HAL_OK)
            Error_Handler();

        /* Start ADC conversion used dma*/
        if (HAL_ADC_Start_DMA(&hadc3, (uint32_t *)DCM_AnalogIn_Buffer.DCM3_ANALOGIN, DCM_ANALOGIN_Size) != HAL_OK)
            Error_Handler();
        break;

    case DCModule_4:
        /* Run the ADC calibration in single-ended mode */
        if (HAL_ADCEx_Calibration_Start(&hadc4, ADC_SINGLE_ENDED) != HAL_OK)
            Error_Handler();

        /* Start ADC conversion used dma*/
        if (HAL_ADC_Start_DMA(&hadc4, (uint32_t *)DCM_AnalogIn_Buffer.DCM4_ANALOGIN, DCM_ANALOGIN_Size) != HAL_OK)
            Error_Handler();
        break;

    case DCModule_5:
        /* Run the ADC calibration in single-ended mode */
        if (HAL_ADCEx_Calibration_Start(&hadc5, ADC_SINGLE_ENDED) != HAL_OK)
            Error_Handler();

        /* Start ADC conversion used dma*/
        if (HAL_ADC_Start_DMA(&hadc5, (uint32_t *)DCM_AnalogIn_Buffer.DCM5_ANALOGIN, DCM_ANALOGIN_Size) != HAL_OK)
            Error_Handler();
        break;

    default:
        LOG_error("calibrate analogin channel error!\r\n");
        break;
    }
}

void stop_analogin(uint8_t ch)
{
    switch (ch)
    {
    case DCModule_1:
        /* Stop ADC2 conversion */
        if (HAL_ADC_Stop_DMA(&hadc2) != HAL_OK)
            Error_Handler();
        break;

    case DCModule_2:
        /* Stop ADC1 conversion */
        if (HAL_ADC_Stop_DMA(&hadc1) != HAL_OK)
            Error_Handler();
        break;

    case DCModule_3:
        /* Stop ADC3 conversion */
        if (HAL_ADC_Stop_DMA(&hadc3) != HAL_OK)
            Error_Handler();
        break;

    case DCModule_4:
        /* Stop ADC4 conversion */
        if (HAL_ADC_Stop_DMA(&hadc4) != HAL_OK)
            Error_Handler();
        break;

    case DCModule_5:
        /* Stop ADC5 conversion */
        if (HAL_ADC_Stop_DMA(&hadc5) != HAL_OK)
            Error_Handler();
        break;

    default:
        LOG_error("calibrate analogin channel error!\r\n");
        break;
    }
}

/**
 * @brief 保存数据到FLASH
 * 
 */
uint8_t dcm_saved_data_toFLASH(uint32_t startaddr, uint32_t len, uint8_t *data)
{
    uint8_t issaved = 0;
    //如果保存失败，重试3次
    for (int i = 0; i < 3; i++)
    {
        if (ee_SavetoFLASH(startaddr, len, data) == true)
        {
            LOG_info("Saved data to FLASH Success! \r\n");
            issaved = 1;
            break;
        }
        else
            LOG_error("Saved data to FLASH faild!!!\r\n");
    }
    //if (!issaved)
    //    Error_Handler();
    return issaved;
}

#ifdef USE_AdjustFunc
/**
 * @brief 从FLASH中读取所有参数
 * 
 */
void dcm_read_data_fromFLASH(void)
{
    uint16_t ee_use_sf_16;
    uint8_t currgain_data[500];    //ee_read_data[500];

    /* 先赋值默认数据 */
    memcpy(DCM_SetCurr_Gain_Flash, DCM_SetCurr_Gain_Default, sizeof(uint16_t) * DCModuleNum * DCM_Gain_Num);
    memcpy(DCM_OUTCurr_Gain_Flash, DCM_OUTCurr_Gain_Default, sizeof(uint16_t) * DCModuleNum * DCM_Gain_Num);    
    /* 读取保存参数的页面中的所有数据 */
    if (ee_read(0, sizeof(currgain_data), currgain_data) == true)
    {
        /* 如果FLASH中有‘DCM_SetCurr_Gain’ 和 ‘DCM_OUTCurr_Gain’参数数据，则采用FLASH中的参数；
         * 如果没有，则采用默认参数：‘DCM_SetCurr_Gain_Default’ 和 ‘DCM_OUTCurr_Gain_Default’ */
        ee_use_sf_16 = currgain_data[0] + (currgain_data[1] << 8);
        if (ee_use_sf_16 == ee_use_StartFrame)
        {
            /* 读取校准数据 */
            LOG("in 'dcm_read_data_fromFLASH', [DCM_SetCurr_Gain_Flash , DCM_OUTCurr_Gain_Flash] : ");
            for (int i = 0; i < DCModuleNum; i++)
            {
                for (int j = 0; j < DCM_Gain_Num; j++)
                {
                    uint32_t setcurrgain_baseaddr = _EE_USE_SetCurrGain_START_ADDR + i * DCM_Gain_Num * 2 + j * 2;
                    DCM_SetCurr_Gain_Flash[i][j] = word(currgain_data[setcurrgain_baseaddr + 1], currgain_data[setcurrgain_baseaddr]);  //i * DCM_Gain_Num * 2 + j * 2 + 2
  
                    uint32_t outcurrgain_baseaddr = _EE_USE_OUTCurrGain_START_ADDR + i * DCM_Gain_Num * 2 + j * 2;
                    DCM_OUTCurr_Gain_Flash[i][j] = word(currgain_data[outcurrgain_baseaddr + 1], currgain_data[outcurrgain_baseaddr]);
                        
                    LOG(" [%d, %d] ", DCM_SetCurr_Gain_Flash[i][j], DCM_OUTCurr_Gain_Flash[i][j]);
                }
            }
            LOG(".......\r\n");
            //have_para_inflash = 1;
            LOG_info("read data from FLASH success! \r\n");
        }
        else
        {
            memset(currgain_data, 0, sizeof(currgain_data));
            currgain_data[0] = lowByte(ee_use_StartFrame);
            currgain_data[1] = highByte(ee_use_StartFrame);
            memcpy(currgain_data + _EE_USE_SetCurrGain_START_ADDR, DCM_SetCurr_Gain_Default, sizeof(uint16_t) * DCModuleNum * DCM_Gain_Num);
            memcpy(currgain_data + _EE_USE_OUTCurrGain_START_ADDR, DCM_OUTCurr_Gain_Default, sizeof(uint16_t) * DCModuleNum * DCM_Gain_Num);   
            dcm_saved_data_toFLASH(0, sizeof(currgain_data), currgain_data);    //ee_SavetoFLASH(0, sizeof(currgain_data), currgain_data);
        }
    } 
    else
    {
        LOG_error("read data from FLASH faild!");
        Error_Handler();
    }

    
    uint8_t adj_dcm_curr[100];
    /* 先赋值默认数据 */
    //memset(Adj_DCM_Curr_Flash, 0, sizeof(uint8_t) * DCModuleNum * ADJ_Curr_Gear_Num);

    /* 读取保存参数的页面中的所有数据 */
    if (ee_read(_EE_USE_AdjustCurr_START_ADDR, sizeof(adj_dcm_curr), adj_dcm_curr) == true)
    {
        /* 如果FLASH中有Adj_DCM_Curr的数据，则采用FLASH中的参数；
         * 如果没有，则默认都设置为 0 */
        ee_use_sf_16 = adj_dcm_curr[0] + (adj_dcm_curr[1] << 8);
        if (ee_use_sf_16 == ee_use_StartFrame)
        {
            LOG("in 'dcm_read_data_fromFLASH', [Adj_DCM_Curr_Flash] : ");
            memcpy(Adj_DCM_Curr_Flash, adj_dcm_curr + 2, sizeof(uint8_t) * DCModuleNum * ADJ_Curr_Gear_Num);
        }
        else
        {
            memset(adj_dcm_curr, 100, sizeof(adj_dcm_curr));          //100
            adj_dcm_curr[0] = lowByte(ee_use_StartFrame);
            adj_dcm_curr[1] = highByte(ee_use_StartFrame);
            dcm_saved_data_toFLASH(_EE_USE_AdjustCurr_START_ADDR, sizeof(adj_dcm_curr), adj_dcm_curr);   //ee_SavetoFLASH(_EE_USE_AdjustCurr_START_ADDR, sizeof(adj_dcm_curr), adj_dcm_curr);
        }
    } 
    else
    {
        LOG_error("read data from FLASH faild!");
        Error_Handler();
    }
    //have_para_inflash = 0;
}
#endif


/**
 *卡尔曼滤波器
    float LastP;//上次估算协方差 初始化值为0.02
    float Now_P;//当前估算协方差 初始化值为1
    float Last_out;//上次卡尔曼滤波器输出 初始化值为0
    float out;//卡尔曼滤波器输出 初始化值为0
    float Kg;//卡尔曼增益 初始化值为0
    float Q;//过程噪声协方差 初始化值为0.0001  Q值越大，比较相信测量值；Q值越小，比较相信预测值，Q越小，滤波越平滑，但滤波结果越滞后
    float R;//观测噪声协方差 初始化值为5
    示例参数：KFP KFP_DCM5 = {0.0, 1, 0, 0.0, 0.0, 0.01, 4.5};
 *@param KFP *kfp 卡尔曼结构体参数
 *   float input 需要滤波的参数的测量值（即传感器的采集值）
 *@return 滤波后的参数（最优值）
 */
#if 1
float kalmanFilter(KFP *kfp, float input)
{
    if (abs(_KFP_Last_out - input) >= 10)
        kfp->Last_out = input * 0.382 + kfp->Last_out * 0.618;

    // 预测协方差方程：k时刻系统估算协方差 = k-1时刻的系统协方差 + 过程噪声协方差
    kfp->Now_P = kfp->LastP + kfp->Q;
    // 卡尔曼增益方程：卡尔曼增益 = k时刻系统估算协方差 / （k时刻系统估算协方差 + 观测噪声协方差）
    kfp->Kg = kfp->Now_P / (kfp->Now_P + kfp->R);
    // 更新最优值方程：k时刻状态变量的最优值 = 状态变量的预测值 + 卡尔曼增益 * （测量值 - 状态变量的预测值）
    kfp->out = kfp->Last_out + kfp->Kg * (input - kfp->Last_out);        //kfp->out = kfp->out + kfp->Kg * (input - kfp->out); // 因为这一次的预测值就是上一次的输出值
    // 更新协方差方程: 本次的系统协方差付给 kfp->LastP 威下一次运算准备。
    kfp->LastP = (1 - kfp->Kg) * kfp->Now_P;
    kfp->Last_out = kfp->out;
    return kfp->out;
}
#endif

KFP* KFP_DCM_Curr_Index(uint8_t ch)
{
    KFP* dcm_kfp;
    switch(ch)
    {
        case DCModule_1:
            dcm_kfp = &KFP_DCM1;
            break;

        case DCModule_2:
            dcm_kfp = &KFP_DCM2;
            break;
        
        case DCModule_3:
            dcm_kfp = &KFP_DCM3;
            break;

        case DCModule_4:
            dcm_kfp = &KFP_DCM4;
            break;

        case DCModule_5:
            dcm_kfp = &KFP_DCM5;
            break;
        
        default:
            dcm_kfp = &KFP_DCM1;
            LOG_error("KFP_DCM_Curr_Index !\r\n");
    }
    return dcm_kfp;
}

/**
 * @brief 获取校准数据的分段数值 1～10
 * 
 */
uint8_t Get_AdjCurrGear_NO(float curr)
{
    uint8_t gear_no = 0;
    if (curr > 0.5 && curr <= 1.5)
        gear_no = 1;
    else if (curr > 1.5 && curr <= 3)
        gear_no = 2;
    else if (curr > 3 && curr <= 4.5)
        gear_no = 3;
    else if (curr > 4.5 && curr <= 6)
        gear_no = 4;
    else if (curr > 6 && curr <=7.5)
        gear_no = 5;
    else if (curr > 7.5 && curr <= 9)
        gear_no = 6;
    else if (curr > 9 && curr <= 10.5)
        gear_no = 7;
    else if (curr > 10.5 && curr <= 12)
        gear_no = 8;
    else if (curr > 12 && curr <= 13.5)
        gear_no = 9;
    else if (curr > 13.5 && curr <= 15)
        gear_no = 10;
    else 
        gear_no = 0;

    return gear_no;
}

/**
 * @brief 获取校准后的电流值
 * 校准后电流值 = 用户设置的输出电流值 * Adjust的百分比
 * 比如：用户设置的输出电流值为10A，设置的校准百分比为120；则校准后的电流值(即：实际输出的电流值)为：10A * 120 / 100 = 12A
 *
 * @param ch 指向具体的某个直流通道
 * @param curr 用户设置的输出电流值
 * @return uint8_t 校准的百分比数值
 *
 * @note 这个函数是为了解决客户负载一致性不好的问题，校准的百分比数值由PLC传过来，然后保存到FLASH中，掉电依然存在。
 */
#if 0
uint8_t Get_AdjustCurr(uint8_t ch)
{
    uint8_t gear_no = Get_AdjCurrGear_NO(DCM_SetOutCurr_Buffer[ch]);
    uint8_t curr_adjust = 100;
    if (Adj_DCM_Curr_Flash[ch][gear_no] != 0)
        curr_adjust = Adj_DCM_Curr_Flash[ch][gear_no];
    else
    {
        if (Adj_DCM_Curr_Flash[ch][0] != 0)
            curr_adjust = Adj_DCM_Curr_Flash[ch][0];
    }
    Get_AdjustCurr_Now[ch] = curr_adjust;
    return curr_adjust;     //return curr * curr_adjust / 100.0;
}
#endif

/**
 * @brief 用于打印LOG
 * 
 */
char *DCModule_State_Log(DCModule_State_t dcmstate)
{
    char * dcmsl = "No LOG!";
    switch(dcmstate)
    {
        case DCMState_Work:
            dcmsl = "Working Fine!";
            break;

        case DCMState_Adjust_Saved:
            dcmsl = "DCM Adjust Param Saved!";
            break;

        case DCMState_OUT_OverCurr:
            dcmsl = "OUTPUT Over Current!";
            break;
        
        case DCMState_IN_NoVolt:
            dcmsl = "INPUT No Voltage!";
            break;

        case DCMState_OUT_Break:
            dcmsl = "OUTPUT Break!";
            break;

        case DCMState_Fault:
            dcmsl = "DC Module Fault!";
            break;

        case DCMState_Adjust_SetData_Err:
            dcmsl = "Set Adj DCM Curr Value Error!";
            break;

        case DCMState_Adjust_Save_Err:
            dcmsl = "Save 'Adj DCM Curr Value' to FLASH Error!";
            break;

        case DCMState_Set_OutCurr_Err:
            dcmsl = "Set Output Current Error!";
            break;
        
        default:
            //LOG_error("DCModule_State_Log !\r\n");
            break;
    }
    return dcmsl;
}